import { Inject, Provide } from "@midwayjs/core";
import { InjectEntityModel } from "@midwayjs/typeorm";
import { Repository } from "typeorm";
import { BblPrizeGroup } from "../entity/prize.group.entity";
import {
  PrizeGroupCreateDto,
  PrizeGroupListQueryDto,
  PrizeGroupPageQueryDto,
  PrizeGroupListDto,
  PrizeGroupInfoDto,
  PrizeGroupUpdateDto
} from "../dto/prize.group.dto";
import { Utils } from "../utils";
import { BblPrize } from "../entity/prize.entity";
import { BblPrizeActivity } from "../entity/prize.activity.entity";
import { BblPrizeResult } from "../entity/prize.result.entity";

@Provide()
export class PrizeGroupService {
  @InjectEntityModel(BblPrizeGroup)
  prizeGroupRepo: Repository<BblPrizeGroup>;

  @InjectEntityModel(BblPrize)
  prizeRepo: Repository<BblPrize>;

  @InjectEntityModel(BblPrizeActivity)
  activityRepo: Repository<BblPrizeActivity>;

  @InjectEntityModel(BblPrizeResult)
  resultRepo: Repository<BblPrizeResult>;

  @Inject()
  utils: Utils;

  /**
   * 创建抽奖活动
   * @param dto 创建活动所需数据
   * @param creatorId 创建人ID
   * @param creatorName 创建人姓名
   * @returns 创建成功的活动详情
   */
  async createPrizeGroup(
    dto: PrizeGroupCreateDto,
    creatorId: string,
    creatorName: string
  ): Promise<PrizeGroupInfoDto> {
    const prizeGroup = this.prizeGroupRepo.create({
      id: this.utils.snowFlake.generate(),
      name: dto.name,
      description: dto.description || null,
      status: dto.status || 0, // 默认为未开始状态
      startTime: dto.startTime ? new Date(dto.startTime) : null,
      endTime: dto.endTime ? new Date(dto.endTime) : null,
      creatorId: creatorId // 对应数据库中的CREATED_BY字段
    });

    const saved = await this.prizeGroupRepo.save(prizeGroup);
    // 创建自定义的响应对象，添加前端所需的字段
    const result = new PrizeGroupInfoDto(saved);
    // 手动设置前端所需的字段值
    result.creatorName = creatorName;

    return result;
  }

  /**
   * 查询抽奖活动列表（不分页）
   * @param query 查询条件
   * @returns 活动列表
   */
  async list(query: PrizeGroupListQueryDto): Promise<PrizeGroupListDto[]> {
    const qb = this.prizeGroupRepo.createQueryBuilder("group");

    if (query.name) {
      qb.andWhere("group.name like :name", {
        name: `%${query.name}%`
      });
    }
    if (query.status !== undefined) {
      qb.andWhere("group.status = :status", { status: query.status });
    }

    const list = await qb.orderBy("group.createdAt", "DESC").getMany();

    // 转换为前端所需的数据结构，添加前端所需的额外字段
    return list.map((item) => {
      const dto = new PrizeGroupListDto(item);
      // 设置前端所需的字段，但在数据库中不存在
      dto.creatorName = "未知"; // 数据库中没有存储创建人姓名，使用默认值
      return dto;
    });
  }

  /**
   * 查询抽奖活动分页列表
   * @param query 分页查询条件
   * @returns 分页数据
   */
  async page(query: PrizeGroupPageQueryDto): Promise<{
    total: number;
    list: PrizeGroupListDto[];
    pageSize: number;
    current: number;
  }> {
    const qb = this.prizeGroupRepo.createQueryBuilder("group");

    if (query.name) {
      qb.andWhere("group.name like :name", {
        name: `%${query.name}%`
      });
    }
    if (query.status !== undefined) {
      qb.andWhere("group.status = :status", { status: query.status });
    }

    const pageSize = parseInt(query.pageSize, 10) || 10;
    const current = parseInt(query.current, 10) || 1;

    const [list, total] = await qb
      .orderBy("group.createdAt", "DESC")
      .skip((current - 1) * pageSize)
      .take(pageSize)
      .getManyAndCount();

    // 转换为前端所需的数据结构，添加前端所需的额外字段
    const resultList = list.map((item) => {
      const dto = new PrizeGroupListDto(item);
      // 设置前端所需的字段，但在数据库中不存在
      dto.creatorName = "未知"; // 数据库中没有存储创建人姓名，使用默认值
      return dto;
    });

    return {
      total,
      list: resultList,
      pageSize,
      current
    };
  }

  /**
   * 获取抽奖活动详情
   * @param id 活动ID
   * @returns 活动详情，不存在则返回null
   */
  async info(id: string): Promise<PrizeGroupInfoDto | null> {
    const prizeGroup = await this.prizeGroupRepo.findOne({
      where: { id }
    });

    if (!prizeGroup) return null;

    // 创建自定义的响应对象，添加前端所需的字段
    const result = new PrizeGroupInfoDto(prizeGroup);
    // 手动设置前端所需的字段值
    result.creatorName = "未知"; // 数据库中没有存储创建人姓名，使用默认值
    result.updaterName = "未知"; // 数据库中没有存储更新人姓名，使用默认值

    return result;
  }

  /**
   * 更新抽奖活动
   * @param dto 更新数据
   * @param updaterId 更新人ID
   * @param updaterName 更新人姓名
   * @returns 更新是否成功
   */
  async update(
    dto: PrizeGroupUpdateDto,
    updaterId: string,
    updaterName: string
  ): Promise<boolean> {
    const prizeGroup = await this.prizeGroupRepo.findOne({
      where: { id: dto.id }
    });

    if (!prizeGroup) return false;

    // 更新字段
    if (dto.name !== undefined) prizeGroup.name = dto.name;
    if (dto.description !== undefined) prizeGroup.description = dto.description;
    if (dto.status !== undefined) prizeGroup.status = dto.status;
    if (dto.startTime !== undefined)
      prizeGroup.startTime = new Date(dto.startTime);
    if (dto.endTime !== undefined) prizeGroup.endTime = new Date(dto.endTime);

    // 更新人信息
    prizeGroup.updaterId = updaterId; // 对应数据库中的UPDATED_BY字段

    await this.prizeGroupRepo.save(prizeGroup);
    return true;
  }

  /**
   * 检查并更新活动状态
   * 根据当前时间自动更新活动状态：
   * - 如果当前时间在开始时间之前，状态为"未开始"(0)
   * - 如果当前时间在开始和结束时间之间，状态为"进行中"(1)
   * - 如果当前时间在结束时间之后，状态为"已结束"(2)
   * @returns 更新的活动数量
   */
  async autoUpdateStatus(): Promise<number> {
    const now = new Date();

    // 更新未开始到进行中
    const toRunning = await this.prizeGroupRepo
      .createQueryBuilder()
      .update(BblPrizeGroup)
      .set({ status: 1 })
      .where("status = 0")
      .andWhere("startTime <= :now", { now })
      .andWhere("endTime > :now OR endTime IS NULL", { now })
      .execute();

    // 更新进行中到已结束
    const toEnded = await this.prizeGroupRepo
      .createQueryBuilder()
      .update(BblPrizeGroup)
      .set({ status: 2 })
      .where("status = 1")
      .andWhere("endTime <= :now", { now })
      .execute();

    return toRunning.affected + toEnded.affected;
  }

  /**
   * 取消抽奖活动
   * @param id 活动ID
   * @param updaterId 更新人ID
   * @param updaterName 更新人姓名
   * @returns 取消是否成功
   */
  async cancel(
    id: string,
    updaterId: string,
    updaterName: string
  ): Promise<boolean> {
    const prizeGroup = await this.prizeGroupRepo.findOne({
      where: { id }
    });

    if (!prizeGroup) return false;

    // 已结束的活动不能取消
    if (prizeGroup.status === 2) return false;

    prizeGroup.status = 3; // 已取消
    prizeGroup.updaterId = updaterId; // 对应数据库中的UPDATED_BY字段

    await this.prizeGroupRepo.save(prizeGroup);
    return true;
  }

  /**
   * 根据状态获取活动统计
   * @returns 各状态活动数量
   */
  async getStatusStatistics(): Promise<{
    total: number;
    notStarted: number;
    running: number;
    ended: number;
    canceled: number;
  }> {
    const qb = this.prizeGroupRepo.createQueryBuilder("group");

    const [notStarted, running, ended, canceled, total] = await Promise.all([
      qb.clone().where("group.status = 0").getCount(),
      qb.clone().where("group.status = 1").getCount(),
      qb.clone().where("group.status = 2").getCount(),
      qb.clone().where("group.status = 3").getCount(),
      qb.clone().getCount()
    ]);

    return {
      total,
      notStarted,
      running,
      ended,
      canceled
    };
  }

  /**
   * 删除抽奖活动（物理删除）
   * @param id 活动ID
   * @returns 删除是否成功
   */
  async remove(id: string) {
    // 先查找活动是否存在
    const prizeGroup = await this.prizeGroupRepo.findOne({ where: { id } });
    if (!prizeGroup) return { success: false, message: "活动不存在" };

    // 检查是否有关联的奖品
    const prizeCount = await this.prizeRepo.count({
      where: { prizeGroup: { id } }
    });
    if (prizeCount > 0) return { success: false, message: "活动有关联的奖品" };

    // 检查是否有关联的活动批次
    const activityCount = await this.activityRepo.count({
      where: { prizeGroup: { id } }
    });
    if (activityCount > 0)
      return { success: false, message: "活动有关联的活动批次" };

    // 检查是否有关联的抽奖结果（通过奖品关联）
    const resultFromPrizeCount = await this.resultRepo
      .createQueryBuilder("result")
      .innerJoin("result.prize", "prize")
      .innerJoin("prize.prizeGroup", "prizeGroup")
      .where("prizeGroup.id = :id", { id })
      .getCount();
    if (resultFromPrizeCount > 0)
      return { success: false, message: "活动有关联的抽奖结果" };

    // 检查是否有关联的抽奖结果（通过活动批次关联）
    const resultFromActivityCount = await this.resultRepo
      .createQueryBuilder("result")
      .innerJoin("result.activityBatch", "activity")
      .innerJoin("activity.prizeGroup", "prizeGroup")
      .where("prizeGroup.id = :id", { id })
      .getCount();
    if (resultFromActivityCount > 0)
      return { success: false, message: "活动有关联的抽奖结果" };

    // 物理删除
    await this.prizeGroupRepo.remove(prizeGroup);
    return { success: true, message: "活动删除成功" };
  }

  /**
   * 检查活动关联的奖品权重总和是否等于100
   * @param groupId 奖品组ID
   * @returns 检查结果，包含是否成功和消息
   */
  async checkGroupPrizeWeight(groupId: string) {
    try {
      // 先查找活动是否存在
      const prizeGroup = await this.prizeGroupRepo.findOne({
        where: { id: groupId }
      });
      if (!prizeGroup) {
        return { success: false, message: "抽奖活动不存在" };
      }

      // 查询关联的所有奖品
      const prizes = await this.prizeRepo.find({
        where: {
          prizeGroup: { id: groupId },
          isDeleted: 0 // 排除已删除的奖品
        },
        order: { weight: "DESC" } // 按权重降序排列
      });

      // 如果没有关联奖品，直接返回成功
      if (prizes.length === 0) {
        return {
          success: false,
          message: "暂无关联奖品",
          data: {
            weightSum: 0,
            prizes: []
          }
        };
      }

      // 计算权重总和
      const weightSum = prizes.reduce((sum, prize) => sum + prize.weight, 0);

      // 格式化奖品信息用于返回
      const prizeList = prizes.map((prize) => ({
        id: prize.id,
        name: prize.prizeName,
        weight: prize.weight,
        percentage: ((prize.weight / weightSum) * 100).toFixed(2) + "%"
      }));

      // 检查权重总和是否等于100
      if (weightSum === 100) {
        return {
          success: true,
          message: "奖品权重总和等于100，配置正确",
          data: {
            weightSum,
            prizes: prizeList
          }
        };
      } else {
        return {
          success: false,
          message: `奖品权重总和为${weightSum}，需要调整为100`,
          data: {
            weightSum,
            prizes: prizeList
          }
        };
      }
    } catch (error) {
      return {
        success: false,
        message: `检查奖品权重失败: ${error.message}`
      };
    }
  }
}
